package imse.team1.grapeorder.ws;


import imse.team1.grapesordering.CancelGrapesOrderRespElement;
import imse.team1.grapesordering.CheckGrapesAvailabilityRespElement;
import imse.team1.grapesordering.PlaceGrapesOrderRespElement;
import imse.team1.grapesorderings.data.*;
import imse.team1.grapesorder.ws.client.*;
import java.io.*;
import java.rmi.RemoteException;
import java.util.*;

/**
 * Created by IntelliJ IDEA.
 * User: Evgenia
 * Date: 6/23/12
 * Time: 1:46 AM
 * To change this template use File | Settings | File Templates.
 */
public class GrapesOrderingServiceSkeleton implements GrapesOrderingServiceSkeletonInterface {
    public final static String GRAPES_AVAL = "grapeproducer/grape_availability.properties";
    public final static String GRAPES_PRICE = "grapeproducer/grape_price.properties";
    public final static String GRAPES_TYPES = "grapeproducer/grape_types.properties";
    public final static String PLACED_ORDERS = "grapeproducer/placed_orders.properties";
    public final static String TEMP_ORDERS = "grapeproducer/temp_orders.properties";

    private static HashMap<String, Integer> grapeAval = new HashMap<String, Integer>();
    private static HashMap<String, Double> grapePrice = new HashMap<String, Double>();
    private static HashMap<String, String> grapeTypes = new HashMap<String, String>();
    private static HashMap<String, Integer> placedOrders = new HashMap<String, Integer>();
    private static HashMap<String, Integer> tempOrders = new HashMap<String, Integer>();
   // private ArrayList<String> grapeOrdersIdsForDelivery = new ArrayList<String>();
    static {

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                saveCacheIntoFiles();
            }
        });


        try {
            Properties prop = new Properties();
            prop.load(new FileInputStream(GRAPES_TYPES));

            Iterator iter = prop.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry entry = (Map.Entry) iter.next();
                grapeTypes.put(
                        (String) entry.getKey(), (String) entry.getValue());
            }

            Properties prop1 = new Properties();
            prop1.load(new FileInputStream(GRAPES_AVAL));
            Iterator iter1 = prop1.entrySet().iterator();
            while (iter1.hasNext()) {
                Map.Entry entry = (Map.Entry) iter1.next();
                String temp = (String) entry.getValue();
                grapeAval.put(
                        (String) entry.getKey(), Integer.parseInt(temp));
            }

            Properties prop2 = new Properties();
            prop2.load(new FileInputStream(GRAPES_PRICE));
            Iterator iter2 = prop2.entrySet().iterator();
            while (iter2.hasNext()) {
                Map.Entry entry = (Map.Entry) iter2.next();
                String temp = (String) entry.getValue();
                grapePrice.put(
                        (String) entry.getKey(), Double.parseDouble(temp));
            }

            Properties prop3 = new Properties();
            prop3.load(new FileInputStream(TEMP_ORDERS));
            Iterator iter3 = prop3.entrySet().iterator();
            while (iter3.hasNext()) {
                Map.Entry entry1 = (Map.Entry) iter3.next();
                String temp = (String) entry1.getValue();
                placedOrders.put(
                        (String) entry1.getKey(), Integer.parseInt(temp));
            }

            Properties prop4 = new Properties();
            prop4.load(new FileInputStream(PLACED_ORDERS));
            Iterator iter4 = prop4.entrySet().iterator();
            while (iter4.hasNext()) {
                Map.Entry entry = (Map.Entry) iter4.next();
                String temp = (String) entry.getValue();
                tempOrders.put(
                        (String) entry.getKey(), Integer.parseInt(temp));
            }


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public CheckGrapesAvailabilityRespElement checkGrapesAvailability(PackageUnit _package) {
        //preparing for the response to the checkAval request
        CheckGrapesAvailabilityRespElement grapesAval = new CheckGrapesAvailabilityRespElement();


        // generate order for the check grapes availability
        String grapesOderId = UUID.randomUUID().toString();

        OrderItem[] orderItems = _package.getOrderItem();
        boolean allAval = false;
        // total number of items in order
        Integer totalItemsInOrder = orderItems.length;

        Integer itemIndex = 0;
        Double sumTotalPrice = 0.00;

        for (OrderItem orderItem : orderItems) {
            String verifyGrapeId = orderItem.getGrapeID();
            Integer verifyGrapeQuant = orderItem.getQty();

            Iterator iter1 = grapeAval.entrySet().iterator();
            while (iter1.hasNext()) {
                Map.Entry pairs = (Map.Entry) iter1.next();
                String grapeTypeID = (String) pairs.getKey();
                Integer grapeTypeAval = (Integer) pairs.getValue();
                if (verifyGrapeId.equalsIgnoreCase(grapeTypeID) && grapeTypeAval >= verifyGrapeQuant) {
                    //subtract from the aval grapes
                    pairs.setValue(grapeTypeAval - verifyGrapeQuant);
                    // key is GrapeOrderId, GrapeTypeId
                    String formKey = grapesOderId + "," + verifyGrapeId;
                    // form value - which is quantity
                    tempOrders.put(formKey, verifyGrapeQuant);
                    // in order to show that the wine type was found
                    allAval = true;
                    break;
                }
            } // while end

            // in for
            //while ended, verify if the grapeType was found and set flag to false
            // if one grapeType was not found there is no need to look for others, order is rejected
            //so that the client (WinProducer) can restart the checkOrder with a new order
            if (!allAval) {
                // order os rejected and 0 order ID is returned
                Availability aval = new Availability();
                aval.setAvailability(false);
                OrderID ordID = new OrderID();
                ordID.setOrderID("00-00-00-00-00");
                TotalPrice tprice = new TotalPrice();
                tprice.setTotalPrice(0.00);
                grapesAval.setAvailability(aval);
                grapesAval.setTotalPrice(tprice);
                grapesAval.setOrderID(ordID);
                break;
            } else {
                allAval = false;
                sumTotalPrice = sumTotalPrice + verifyGrapeQuant * grapePrice.get(verifyGrapeId);
            }

            if (itemIndex == (totalItemsInOrder - 1)) {
                Availability aval = new Availability();
                aval.setAvailability(true);
                TotalPrice tprice = new TotalPrice();
                tprice.setTotalPrice(sumTotalPrice);
                OrderID ordID = new OrderID();
                ordID.setOrderID(grapesOderId);
                grapesAval.setAvailability(aval);
                grapesAval.setTotalPrice(tprice);
                grapesAval.setOrderID(ordID);
            }

            itemIndex++;
        }

        return grapesAval;
    }


    public PlaceGrapesOrderRespElement placeGrapesOrder(OrderID orderID) {
        String verifyOrdrId = orderID.getOrderID();
        boolean GrapeOrderFound = false;
        ArrayList<String> getKeysToRemove = new ArrayList<String>();

        Iterator iter1 = tempOrders.entrySet().iterator();
        while (iter1.hasNext()) {
            Map.Entry pairs = (Map.Entry) iter1.next();
            String key = (String) pairs.getKey();
            String[] ordIdItemId = key.split(",");
            String ordrID = ordIdItemId[0];

            if (ordrID.equalsIgnoreCase(verifyOrdrId)) {
                GrapeOrderFound = true;
                placedOrders.put((String) pairs.getKey(), (Integer) pairs.getValue());
                getKeysToRemove.add((String) pairs.getKey());


                // tempOrders.remove(pairs.getKey()) ;
                // iter1.remove();

            }
        } // while end

        PlaceGrapesOrderRespElement plGrOrdResp = new PlaceGrapesOrderRespElement();
        OrderID ordID = new OrderID();
        ordID.setOrderID(orderID.getOrderID());
        plGrOrdResp.setOrderID(ordID);

        if (GrapeOrderFound) {
            plGrOrdResp.setOrderStatus(OrderStatus.PLACED);
            //grapeOrdersIdsForDelivery.add(getKeysToRemove.get(0).split(",")[0]);
            //DeliveredOrderID = getKeysToRemove.get(0).split(",")[0];
            for (String key : getKeysToRemove) {
                tempOrders.remove(key);
            }

            CachedGrapesOrders.placedGrapesOrders.put(orderID.getOrderID(), orderID);
            Thread deliveryThread= new Thread(new Delivery(orderID.getOrderID()));
            deliveryThread.setDaemon(true);
            deliveryThread.start();

        } else {
            plGrOrdResp.setOrderStatus(OrderStatus.REJECTED);
        }

        return plGrOrdResp;
    }


    public CancelGrapesOrderRespElement cancelGrapesOrder(OrderID orderID2) {
        String verifyOrdrId = orderID2.getOrderID();
        boolean GrapeOrderFound = false;
        ArrayList<String> getKeysToRemove = new ArrayList<String>();

        //to delete from placed
        Iterator iter1 = placedOrders.entrySet().iterator();
        while (iter1.hasNext()) {
            Map.Entry pairs = (Map.Entry) iter1.next();
            String key = (String) pairs.getKey();
            String[] ordIdItemId = key.split(",");
            String ordrID = ordIdItemId[0];

            if (ordrID.equalsIgnoreCase(verifyOrdrId)) {
                GrapeOrderFound = true;
                getKeysToRemove.add((String) pairs.getKey());
                // tempOrders.remove(pairs.getKey()) ;
                // iter1.remove();

            }
        } // while end

        CancelGrapesOrderRespElement canGrOrdResp = new CancelGrapesOrderRespElement();
        OrderID ordID = new OrderID();
        ordID.setOrderID(orderID2.getOrderID());
        canGrOrdResp.setOrderID(ordID);

        if (GrapeOrderFound) {
            canGrOrdResp.setOrderStatus(OrderStatus.CANCELLED);

            for (String key : getKeysToRemove) {
                placedOrders.remove(key);
            }

        } else {
            canGrOrdResp.setOrderStatus(OrderStatus.REJECTED);
        }

        return canGrOrdResp;
    }

    public static void saveCacheIntoFiles() {
        try {

            Properties properties = new Properties();
            Iterator it = grapeAval.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry pairs = (Map.Entry) it.next();
                properties.setProperty((String) pairs.getKey(), Integer.toString((Integer) pairs.getValue()));
                it.remove(); // avoids a ConcurrentModificationException
            }
            File file = new File(GRAPES_AVAL);
            FileOutputStream fileOut = new FileOutputStream(file);
            properties.store(fileOut, "Cached Grapes availability");
            fileOut.close();

            Properties properties1 = new Properties();
            Iterator it1 = tempOrders.entrySet().iterator();
            while (it1.hasNext()) {
                Map.Entry pairs = (Map.Entry) it1.next();
                properties1.setProperty((String) pairs.getKey(), Integer.toString((Integer) pairs.getValue()));
                it1.remove(); // avoids a ConcurrentModificationException
            }
            File file1 = new File(TEMP_ORDERS);
            FileOutputStream fileOut1 = new FileOutputStream(file1);
            properties1.store(fileOut1, "Cached temp orders");
            fileOut1.close();

            Properties properties2 = new Properties();
            Iterator it2 = placedOrders.entrySet().iterator();
            while (it2.hasNext()) {
                Map.Entry pairs = (Map.Entry) it2.next();
                properties2.setProperty((String) pairs.getKey(), Integer.toString((Integer) pairs.getValue()));
                it2.remove(); // avoids a ConcurrentModificationException
            }
            File file2 = new File(PLACED_ORDERS);
            FileOutputStream fileOut2 = new FileOutputStream(file2);
            properties2.store(fileOut2, "Cached placed orders");
            fileOut2.close();


        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    class Delivery implements Runnable {

        private String orderid;

          Delivery(String orderid) {
            this.orderid = orderid;
          }

             public void run() {
               try {
                synchronized (CachedGrapesOrders.placedGrapesOrders){
                Thread.currentThread().sleep(2000L);
                //
                OrderID grOrderID = CachedGrapesOrders.placedGrapesOrders.get(orderid);

                    // deliveredOrdNotif.setOrderID(ordID);
                    // deliveredOrdNotif.setOrderStatus(OrderStatus.REJECTED);

                   //call here the web service to notify order was delivered

                    try {

                        GrapesOrderStatusUpdateService updateStatusReceiverService = new GrapesOrderStatusUpdateServiceStub();
                        updateStatusReceiverService.updateGrapedOrderStatus(grOrderID, OrderStatus.DELIVERED);
                       } catch (RemoteException axisFault) {
                        axisFault.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                        throw new RuntimeException(axisFault);
                    }
                    CachedGrapesOrders.placedGrapesOrders.remove(orderid);
                }
               } catch (InterruptedException e) {
                e.printStackTrace();
             }

             }
    }
}

